package com.sky.aspect;

import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * 自定义切面类，用于公共字段发填充
 */
@Component
@Aspect
@Slf4j
public class AutoFillAspect {
    /**
     * 切入点表达式 ：扫描mapper包下的所有类的方法和注解@AutoFill
     */
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void autoFillPointCut(){

    }

    /**
     * 前置通知
     * @param joinPoint
     */
    @Before("autoFillPointCut()")
    public void before(JoinPoint joinPoint){
        log.info("公共字段开始填充{}",joinPoint);
        //目标 ：对指定的方法获取参数对象
        //1 通过joinPoint获取方法签名对象（需要增强的方法）
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        //2 通过方法签名对象获取@AutoFill注解对象
        AutoFill autoFill = methodSignature.getMethod().getAnnotation(AutoFill.class);
        //3 获取注解@AutoFill注解的值（update or insert）
        OperationType value = autoFill.value();
        //4 获取参数对象原始方法的参数数组
        Object[] args = joinPoint.getArgs();
        //5 判断参数数组是否有效，无效结束
        if (args==null || args.length==0){
            return;
        }
        //6 获取增改方法第一个元素，下标0 的参数对象
        Object arg = args[0];
        //7 准备当前时间登录人id
        LocalDateTime now = LocalDateTime.now();
        Long empId = BaseContext.getCurrentId();
        //8 判断@AutoFill注解对象的值如果为Operaition。Insert 填充4个字段吧
        try {
            Method updateUserMethod = arg.getClass().getMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
            Method updateTimeMethod = arg.getClass().getMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
            if(value==OperationType.INSERT){
                // 已知条件,对象obj 方法名字符串
                // 获取set封装数据方法语法 obj.getClass.getMethods("方法名字符串"，参数类型字节码)
                Method createUserMethod = arg.getClass().getMethod(AutoFillConstant.SET_CREAT_USER, Long.class);
                Method createTimeMethod = arg.getClass().getMethod(AutoFillConstant.SET_CREAT_TIME, LocalDateTime.class);
                //执行方法反射语法：method.invoke(方法所属的对象，数据值)
                updateTimeMethod.invoke(arg,now);
                updateUserMethod.invoke(arg,empId);
                createTimeMethod.invoke(arg,now);
                createUserMethod.invoke(arg,empId);
            }else {
                //9 否则，填充2个字段
                updateTimeMethod.invoke(arg,now);
                updateUserMethod.invoke(arg,empId);
            }
        } catch (NoSuchMethodException e) {
          //  throw new RuntimeException(e);
            log.info("公共字段填充失败{}",e.getMessage());
        } catch (InvocationTargetException | IllegalAccessException e) {
            log.info("公共字段填充失败{}",e.getMessage());
        }

    }
}
